﻿using JetBrains.Annotations;
using MugenMvvmToolkit.Interfaces;

namespace MugenMvvmToolkit.Infrastructure
{
    /// <summary>
    ///     Enables loosely-coupled publication of and subscription to events.
    /// </summary>
    public class EventAggregator : IEventAggregator
    {
        #region Fields

        /// <summary>
        /// Gets the collection of observers
        /// </summary>
        protected readonly WeakListenersCollection Observers;

        #endregion

        #region Constructors

        /// <summary>
        ///     Initializes a new instance of the <see cref="EventAggregator" /> class.
        /// </summary>
        public EventAggregator()
        {
            Observers = new WeakListenersCollection();
        }

        /// <summary>
        ///     Initializes a new instance of the <see cref="EventAggregator" /> class.
        /// </summary>
        public EventAggregator([NotNull]IEventAggregator parent)
            : this()
        {
            Should.NotBeNull(parent, "parent");
            parent.Subscribe(this);
        }

        #endregion

        #region Implementation of IEventAggregator

        /// <summary>
        ///     Subscribes an instance to all events declared through implementations of <see cref="IHandler{T}" />
        /// </summary>
        /// <param name="instance">The instance to subscribe for event publication.</param>
        public virtual bool Subscribe(object instance)
        {
            Should.NotBeNull(instance, "instance");
            if (instance == this)
                return false;
            return Observers.Add(instance);            
        }

        /// <summary>
        ///     Unsubscribes the instance from all events.
        /// </summary>
        /// <param name="instance">The instance to unsubscribe.</param>
        public virtual bool Unsubscribe(object instance)
        {
            Should.NotBeNull(instance, "instance");
            if (instance == this)
                return false;
            return Observers.Remove(instance);
        }

        /// <summary>
        ///     Publishes a message.
        /// </summary>
        /// <param name="sender">The object that raised the event.</param>
        /// <param name="message">The message instance.</param>
        public virtual void Publish(object sender, object message)
        {
            Should.NotBeNull(sender, "sender");
            Should.NotBeNull(message, "message");
            Observers.Publish(sender, message);
        }

        #endregion

        #region Implementation of IHandler<in object>

        /// <summary>
        ///     Handles the message.
        /// </summary>
        /// <param name="sender">The object that raised the event.</param>
        /// <param name="message">Information about event.</param>
        void IHandler<object>.Handle(object sender, object message)
        {
            Publish(sender, message);
        }

        #endregion
    }
}